package top.songxs.yygh.service.order.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import top.songxs.mq.consts.MqConst;
import top.songxs.mq.service.RabbitService;
import top.songxs.yygh.common.exp.DiyException;
import top.songxs.yygh.common.utils.HttpRequestHelper;
import top.songxs.yygh.enums.OrderStatusEnum;
import top.songxs.yygh.feign.client.PatientFeignClient;
import top.songxs.yygh.hosp.client.HospitalFeignClient;
import top.songxs.yygh.model.order.OrderInfo;
import top.songxs.yygh.model.user.Patient;
import top.songxs.yygh.service.order.mapper.OrderInfoMapper;
import top.songxs.yygh.service.order.service.OrderService;
import top.songxs.yygh.service.order.service.WeixinService;
import top.songxs.yygh.vo.hosp.ScheduleOrderVo;
import top.songxs.yygh.vo.msm.MsmVo;
import top.songxs.yygh.vo.order.OrderCountQueryVo;
import top.songxs.yygh.vo.order.OrderCountVo;
import top.songxs.yygh.vo.order.OrderMqVo;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderService {
    @Autowired
    PatientFeignClient patientFeignClient;

    @Autowired
    RabbitService rabbitService;

    @Autowired
    HospitalFeignClient hospitalFeignClient;
    @Autowired
    WeixinService weixinService;

    @Override  //返回一个orderId
    public Long saveOrder(String scheduleId, Long patientId) {
        Patient patient = patientFeignClient.getPatientOrder(patientId);
        ScheduleOrderVo scheduleOrderVo = hospitalFeignClient.getScheduleOrderVo(scheduleId);
        String apiUrl = hospitalFeignClient.getApiUrl(scheduleOrderVo.getHoscode());
        //找到那个医院下单  提交订单到医院地址   http://ip:port/order/submitOrder
        String url = "http://" + apiUrl + "/order/submitOrder";

        Map<String, Object> params = new HashMap<>();
        params.put("hoscode", scheduleOrderVo.getHoscode());
        params.put("depcode", scheduleOrderVo.getDepcode());
        params.put("hosScheduleId", scheduleOrderVo.getHosScheduleId());
        params.put("reserveDate", scheduleOrderVo.getReserveDate());
        params.put("reserveTime", scheduleOrderVo.getReserveTime());
        params.put("amount", scheduleOrderVo.getAmount());


        params.put("name", patient.getName());
        params.put("sex", patient.getSex());
        params.put("birthdate", patient.getBirthdate());
        params.put("phone", patient.getPhone());
        params.put("isMarry", patient.getIsMarry());
        params.put("provinceCode", patient.getProvinceCode());
        params.put("cityCode", patient.getCityCode());
        params.put("districtCode", patient.getDistrictCode());
        params.put("address", patient.getAddress());
        params.put("contactsName", patient.getContactsName());
        params.put("contactsCertificatesType", patient.getContactsCertificatesType());
        params.put("contactsCertificatesNo", patient.getContactsCertificatesNo());
        params.put("contactsPhone", patient.getContactsPhone());
        params.put("isInsure", patient.getIsInsure());

        //发起一个Http请求，参数map，地址url
        //JSONObject={ code message data} code 200成功， 其他请求失败
        JSONObject jsonObject = HttpRequestHelper.sendRequest(params, url);
        Integer code = jsonObject.getInteger("code");
        if (200 != code) throw new DiyException(20001, "医院端接口调用失败");
        JSONObject data = jsonObject.getJSONObject("data");
        //data={hosRecordId number reservedNumber availableNumber fetchTime fetchAddress}
        Long hosRecordId = data.getLong("hosRecordId");
        Integer number = data.getInteger("number");
        Integer reservedNumber = data.getInteger("reservedNumber");
        Integer availableNumber = data.getInteger("availableNumber");
        String fetchTime = data.getString("fetchTime");
        String fetchAddress = data.getString("fetchAddress");
        //医院端返回的data数据
        //2、创建平台端的订单 ‘yygh_order'  'order_info'
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setUserId(patient.getUserId());
        orderInfo.setOutTradeNo((new DateTime().toString("yyyyMMdd") + UUID.randomUUID().toString().replace("-", "")).substring(0, 32));
        orderInfo.setHoscode(scheduleOrderVo.getHoscode());
        orderInfo.setHosname(scheduleOrderVo.getHosname());
        orderInfo.setDepcode(scheduleOrderVo.getDepcode());
        orderInfo.setDepname(scheduleOrderVo.getDepname());
        orderInfo.setTitle(scheduleOrderVo.getTitle());
        orderInfo.setScheduleId(scheduleId);
        orderInfo.setReserveDate(scheduleOrderVo.getReserveDate());
        orderInfo.setReserveTime(scheduleOrderVo.getReserveTime());

        //patient设置就诊人信息
        orderInfo.setPatientId(patientId);
        orderInfo.setPatientName(patient.getName());
        orderInfo.setPatientPhone(patient.getPhone());

        //从医院端返回的data里的数据进行设置
        orderInfo.setHosRecordId(hosRecordId + "");
        orderInfo.setNumber(number);
        orderInfo.setFetchTime(fetchTime);
        orderInfo.setFetchAddress(fetchAddress);

        //todo:时间bug
        orderInfo.setAmount(scheduleOrderVo.getAmount());


        orderInfo.setQuitTime(scheduleOrderVo.getQuitTime());  //退号时间

        orderInfo.setOrderStatus(OrderStatusEnum.UNPAID.getStatus());


        int insert = this.baseMapper.insert(orderInfo);
        if (insert < 1) throw new DiyException(20001, "平台端创建订单失败");

        //异步更新mongo中的排版数量
        OrderMqVo orderMqVo = new OrderMqVo();
        orderMqVo.setAvailableNumber(availableNumber);
        orderMqVo.setReservedNumber(reservedNumber);
        orderMqVo.setScheduleId(scheduleId);

        //异步给就诊人发送一个短信通知
        MsmVo msmVo = new MsmVo();
        msmVo.setPhone(patient.getPhone());
        msmVo.getParam().put("message", "【预约挂号】订单创建成功！");
        orderMqVo.setMsmVo(msmVo);
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER, MqConst.ROUTING_ORDER, orderMqVo);


        return orderInfo.getId();
    }

    @Override
    public OrderInfo getByScheduleIdAndPatientId(String scheduleId, Long patientId) {
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(scheduleId) && patientId != null) {
            queryWrapper.eq("schedule_id", scheduleId);
            queryWrapper.eq("patient_id", patientId);
        }

        return this.baseMapper.selectOne(queryWrapper);
    }

    @Override
    public Boolean cancelOrder(Long orderId) {
        //1、查询平台端订单
        OrderInfo orderInfo = this.baseMapper.selectById(orderId);
        Date quitTime = orderInfo.getQuitTime();
        //2、如果退号时间已过，不能取消预约
        DateTime dateTime = new DateTime(quitTime);
        if (dateTime.isBeforeNow()) throw new DiyException(20001, "退号时间已过不能进行退号");
        //3、调用医院端取消预约接口
        HashMap<String, Object> paramMap = new HashMap<>();
        paramMap.put("hoscode", orderInfo.getHoscode());
        paramMap.put("hosRecordId", orderInfo.getHosRecordId());
        String apiUrl = hospitalFeignClient.getApiUrl(orderInfo.getHoscode());
        String url = "http://" + apiUrl + "/order/updateCancelStatus";
        JSONObject jsonObject = HttpRequestHelper.sendRequest(paramMap, url);
        if (jsonObject.getInteger("code") != 200) throw new DiyException(20001, "医院端取消预约接口调用失败！");


        //4、判断订单状态+是否已支付，执行退款流程；退款流程写在weixinService中
        if (orderInfo.getOrderStatus().equals(OrderStatusEnum.PAID.getStatus())){
            Boolean isRefund = weixinService.refund(orderId);
            if (!isRefund) throw new DiyException(20001,"退款失败");
        }
        //5、更改平台端订单状态为已取消
        orderInfo.setOrderStatus(OrderStatusEnum.CANCLE.getStatus());
        this.updateById(orderInfo);
        //6、异步更新mongodb排班号源数量+给就诊人发送短信通知
        OrderMqVo orderMqVo = new OrderMqVo();
        orderMqVo.setScheduleId(orderInfo.getScheduleId());

        MsmVo msmVo = new MsmVo();
        msmVo.setPhone(orderInfo.getPatientPhone());
        msmVo.getParam().put("message","取消预约成功！");
        orderMqVo.setMsmVo(msmVo);
        //医院服务接收到消息后，判断消息中如果存在两个num，说明是创建订单；如果没有两个num说明是取消订单。
        //创建订单时将mg中排班的号源数量更新成医院端返回的两个num
        //取消订单时将mg中排班的号源数量+1即可
        //第订单队列中发送一个消息
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER,MqConst.ROUTING_ORDER,orderMqVo);

        return true;
    }

    @Override
    public Map<String, Object> getCountMap(OrderCountQueryVo orderCountQueryVo) {
        //SELECT reserve_date reserveDate,count(1) count FROM order_info  where hosname like "%协和%"
        //AND reserve_date >= '2023-05-07' AND reserve_date <='2023-05-12'
        //GROUP BY reserve_date ORDER BY reserve_date;
        List<OrderCountVo> list= baseMapper.getCountMap(orderCountQueryVo);
        List<Integer> countList = list.stream().map(OrderCountVo::getCount).collect(Collectors.toList());
        List<String> dateList = list.stream().map(OrderCountVo::getReserveDate).collect(Collectors.toList());
        Map<String, Object> map = new HashMap<>();
        map.put("countList",countList);
        map.put("dateList",dateList);

        return map;
    }

    @Override
    public void patientTips(String message) {
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("reserve_date",message);
        wrapper.eq("order_status",1);
        List<OrderInfo> orderInfos = baseMapper.selectList(wrapper);

        orderInfos.forEach(orderInfo -> {
            String patientName = orderInfo.getPatientName(); //就诊人姓名
            String patientPhone = orderInfo.getPatientPhone();//就诊人电话
            MsmVo msmVo = new MsmVo();
            msmVo.setPhone(patientPhone);
            String mes = patientName+"你好"+"明天记得就诊！";
            //向消息队列发送一条消息
            msmVo.getParam().put("message",mes);
            rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_MSM,MqConst.ROUTING_MSM_ITEM,msmVo);
        });
    }


}
